winbrew_core\fs\archive\extract/
mod.rs

1//! Archive extraction facade.
2//! This module provides a high-level API for extracting archive payloads while
3//! preserving the ZIP security and rollback behavior WinBrew already relies on.
4
5mod gzip;
6mod sevenz;
7mod tar;
8mod zip;
9
10use super::ArchiveKind;
11use crate::fs::{FsError, Result};
12use std::path::Path;
13
14type BoxedResult<T> = std::result::Result<T, Box<FsError>>;
15
16#[cfg(not(windows))]
17use super::platform::PortablePlatform as DefaultPlatform;
18#[cfg(windows)]
19use super::platform::WindowsPlatform as DefaultPlatform;
20
21/// Extracts an archive into `destination_dir`, rejecting entries with invalid paths.
22pub fn extract_archive(
23    archive_kind: ArchiveKind,
24    archive_path: &Path,
25    destination_dir: &Path,
26) -> BoxedResult<()> {
27    match archive_kind {
28        ArchiveKind::Zip => extract_zip_archive_with_limits(
29            archive_path,
30            destination_dir,
31            super::limits::ExtractionLimits::default(),
32        )
33        .map_err(Box::new),
34        ArchiveKind::Gzip => {
35            gzip::extract_gzip_archive(archive_path, destination_dir).map_err(Box::new)
36        }
37        ArchiveKind::SevenZip => {
38            sevenz::extract_sevenz(archive_path, destination_dir).map_err(Box::new)
39        }
40        ArchiveKind::Tar => tar::extract_tar_archive_with_platform::<DefaultPlatform>(
41            archive_path,
42            destination_dir,
43            super::limits::ExtractionLimits::default(),
44        )
45        .map_err(Box::new),
46        _ => Err(Box::new(FsError::archive_backend_unavailable(
47            archive_kind.as_str(),
48        ))),
49    }
50}
51
52/// Extracts a ZIP archive into the destination directory.
53///
54/// The extraction target is validated so the archive cannot be unpacked through
55/// an existing reparse-point ancestor, and symlink entries are refused.
56pub fn extract_zip_archive(zip_path: &Path, destination_dir: &Path) -> BoxedResult<()> {
57    extract_archive(ArchiveKind::Zip, zip_path, destination_dir)
58}
59
60fn extract_zip_archive_with_limits(
61    zip_path: &Path,
62    destination_dir: &Path,
63    limits: super::limits::ExtractionLimits,
64) -> Result<()> {
65    zip::extract_zip_archive_with_platform::<DefaultPlatform>(zip_path, destination_dir, limits)
66}